blah blah blah blah blah blah.
Sigh. I remember when I was first learning to program on Android devices. Like everyone,
I was stunned to find out that during an orientation change, my entire Activity would be
destroyed and then have to redraw itself. WTF? The good programmer deep inside was screaming
his bloody head off: what kind of completely inefficient crap was this?
After all that time and work to go through all those steps to finally get that Activity looking
just right, I now have to destroy it all and start again from the beginning? Aaaaaghh!
But after a while, letting the thoughts go through my head, I kind of figured that there
wasn't really a better solution. And I learned to live with it.
But I found bugs popping up during orientation changes, and I did some more testing and
saw some strange results from my logcat messages. It looked like onCreate()
was being called more than once in some cases of an orientation change.
We all know the Activity Life-cycle, so when there's an orientation change we
expect the Activity to go away in this order: onPause(), onStop(), and then onDestroy().
And then, when the Activity is done all over again for the new orientation, we expect
to see the usual calls of onCreate(), onStart(), and onResume(). But that's not what
was happening. Do it yourself, write some Log.i(...) statements in these and do an
orientation change. I'll wait.
Yup, isn't that weird? Those startup messages are called TWICE! But
not always!
Apparently there is more than one thing happening: an orientation change AND a keyboard
flipping in/out can cause all this ruckus. Thus the multiple restarts and various other
confusions.
I have lots to say about this, but for now I'll just say, blecchh!
That alone is bad enough. But when you add the complexity of an ASyncTask to the loading of
an Activity, you've turned a simple build-a-screen class into a giant mess.
So that's the end of today's rant. This is a mess of steaming crap--a hack upon hack upon
hack that's so hard to maintain that I wish that Google had done a crappy hack
instead of this stupid orientation/ASyncTask stuff. A hack would have been SOOO much easier
to deal with! Damn!
Ok, the last blog was about the horrible implementation of orientation changes
in Android. The fix that Google suggests is to use asynchronous tasks, but
these bring their own sets of issues.
Whenever an Activity needs to do something that takes a bit of time, developers
need to spin that into a separate thread so that the UI thread doesn't get
clogged up (resulting in a less-than-snappy interface at best, an "Application
Not Responding (ANR) crash at worse).
Since so many useful things can take a while (web access, database access,
file access, even complicated user interfaces), the good people at Google thought they'd
provide a built-in way to handle this: ASyncTasks.
It's not an easy thing to master, but I've been doing them so often that ASyncTasks
feel like old classmates.
Aside from their complexity, there are still two problems with ASyncTasks:
Memory Leaks
Non Permanence
Memory Leaks: Let's say you start up your Activity and need to load up some info from
the web. Great, throw up a waiting spinner,
set your ASyncTask to go to the web and fetch your data.
But...before you're done loading the data, the user interrupts you (orientation
change, pops out a keyboard, gets a phone call, etc.). What happens?
Well, your Activity is killed, and a new one is started. This new Activity begins
the process all over again, creating a new ASyncTask to grab that needed info from
the web.
But what happened to that old ASyncTask? It wasn't really connected to the old
Activity, so it wasn't killed when the old Activity died. And when it's done,
it'll hit its onPostExecute() and try to access
your old Activity! Yeah, the one that's now in the garbage collector.
CRASH!
Try it yourself: just rotate quickly several times. It's pretty easy to make
that beautiful program crash like you're back in junior high.
I'd love to say that I've figured everything out, but Ryan has an excellent
article detailing the issues
here.
Non Permanence: That (now static) ASynchronousTask you have now implemented
can only be used once! Yup, try calling
myASyncTaskInstance.execute() a second time
and...whoa, CRASH!
Not quite sure why this happens, but it does. To me, this severely limits
the usability of ASyncTasks as I can't reload my data using this same pattern.
Really!
So what's a guy to do? Avoid all this junk completely and do it the real
Android way: Services. I'll go into this in more detail when
I have time, but here's a hint: IntentService coupled with Parcelable/Serializable
is a truly useful thing.
"Android Evolution" created by Manu Cornet, http://www.bonkersworld.net. All else is copyright 2013 by Scott M. Biggs and Sleep Furiously Productions. Not that that means much these days.